﻿using System;
using System.Collections.Concurrent;
using System.Reflection;

using ApiGateway;
using ApiGateway.Attr;

using HttpWebSocket.Interface;

using RpcHelper;

using WebSocketGateway.Helper;
using WebSocketGateway.Interface;
using WebSocketGateway.Model;

namespace WebSocketGateway.Collect
{
    internal class RouteCollect
    {
        private static readonly ConcurrentDictionary<string, ApiHandler> _RouteApi = new ConcurrentDictionary<string, ApiHandler>();
        #region 注册路由
        private static IRouteConfig _RegApi(Type type, IApiModular modular, Action<IRoute> action)
        {
            ApiPrower prower = (ApiPrower)type.GetCustomAttribute(ApiPublicDict.ProwerAttr);
            ApiRouteName route = (ApiRouteName)type.GetCustomAttribute(ApiPublicDict.ApiRouteName);
            RouteConfig config = new RouteConfig
            {
                Route = route,
                Type = type,
            };
            if (prower != null)
            {
                config.IsAccredit = prower.IsAccredit;
                config.Prower = prower.Prower;
            }
            GatewayService.RegModular(modular, type);
            MethodInfo[] methods = type.GetMethods();
            methods.ForEach(a =>
            {
                if (a.IsPublic && a.DeclaringType == type)
                {
                    if (!_RegApi(a, config, modular, action))
                    {
                        new ErrorLog("gateway.socket.route.reg.fail", "Socket网关路由注册失败!", "Gateway")
                        {
                            {"method",a.Name },
                            { "source",a.DeclaringType.FullName}
                        }.Save();
                    }
                }
            });
            return config;
        }
        private static bool _RegApi(MethodInfo method, IRouteConfig config, IApiModular modular, Action<IRoute> action)
        {
            if (!RouteHelper.CheckFormat(method))
            {
                return false;
            }
            ApiModel model = RouteHelper.GetApiParam(method, config, modular);
            ISocketApi api = RouteHelper.GetApi(model);
            ApiHandler handler = new ApiHandler(api, model, config, modular);
            if (_RouteApi.TryAdd(api.LocalPath, handler))
            {
                handler.RegApi();
                action(handler.Route);
                return true;
            }
            return false;
        }

        public static void RegApi(Type type, IApiController api, IApiModular modular, Action<IRoute> action)
        {
            IRouteConfig config = _RegApi(type, modular, action);
            api?.Install(config);
        }
        public static void RegApi(Type type, IApiModular modular, Action<IRoute> action)
        {
            _RegApi(type, modular, action);
        }
        #endregion

        public static void ExecRoute(IApiService service)
        {
            IUserPage page = ApiHelper.GetPage(service.Request.Content, out byte[] content);
            if (page == null)
            {
                throw new ErrorException("http.web.page.analysis.error");
            }
            else if (!_RouteApi.TryGetValue(page.Direct, out ApiHandler handler))
            {
                throw new ErrorException("http.404");
            }
            else if (!ApiPlugInService.Exec(service, handler, out string error))
            {
                throw new ErrorException(error);
            }
            else
            {
                using (handler)
                {
                    handler.Execute(service, page, content);
                }
            }
        }
    }
}
